# 封装http请求响应断言和数据库断言方法

import allure
from abc import ABC,abstractmethod
from utils.send_request import send_jdbc_request
from utils.base_asserts import *

class DataAssert(ABC):
    """
    http断言的基类
    """
    @abstractmethod
    def http_assert(self,case,res):
        pass


class SingleAssert(DataAssert):
    """
    http单个断言，重写基类http_assert方法
    """

    @allure.step("3.http响应断言")
    def http_assert(self, case, res):
        try:
            if case["check"]:
                # 场景1：检查特定字段的值是否符合预期
                result = GetKeywords.get_keyword(res, case["check"])
                logging.info(f"3.HTTP响应断言：实际值={result}, 期望值={case['expected']}")

                if result == case["expected"]:
                    logging.info(f"✅ 断言成功: 字段 '{case['check']}值匹配'：（实际={result}，期望={case['expected']}）")
                else:
                    error_msg = f"❌ 断言失败: 字段 '{case['check']}'值不匹配。实际值: {result}，期望值: {case['expected']}"
                    logging.error(error_msg)
                    assert False, error_msg

            else:
                # 场景2：检查预期文本是否在响应中
                logging.info(f"3.HTTP响应断言：实际值={res}, 期望值={case['expected']}")

                if case["expected"] in str(res):
                    logging.info(f" ✅ 断言成功: 文本 '{case['expected']}' 存在于响应中")
                else:
                    error_msg = f" ❌ 断言失败: 文本 '{case['expected']}' 未在实际响应中找到\n完整响应: {res}"
                    logging.error(error_msg)
                    assert False, error_msg
        except Exception as e:
            raise  # 重新抛出异常以确保测试标记为失败
    # @allure.step("3.http响应断言")
    # def http_assert(self,case,res):
    #     if case["check"]:
    #         result = GetKeywords.get_keyword(res, case["check"])
    #         logging.info(f"3.HTTP响应断言内容：实际结果({result}) == 预期结果({case['expected']})")
    #         assert result == case["expected"]
    #     else:
    #         logging.info(f"3.HTTP响应断言内容：预期结果({case['expected']})in 实际结果({res}) ")
    #         assert case["expected"] in str(res)

class MultipleAssert(DataAssert):
    """
    http多重断言，重写基类http_assert方法
    """
    @allure.step("3.HTTP多重响应断言")
    def http_assert(self,case, res):
        if case["check"]:
            MainAsserts(case, res).main_assert()

def obj_processor(case):
    """
    对象处理，根据传入case的不同，来返回不同的对象
    :param case:
    :param res:
    :return: 单个断言或者多重断言的对象
    """
    try:
        eval(case["check"])
    except:
        return SingleAssert()
    else:
        return MultipleAssert()

def http_assert(case,res):
    """
    真正的调用逻辑，后续无论怎么新增http返回值的断言，都是调用这个函数
    :param case:测试用例
    :param res:返回结果
    """
    obj_processor(case).http_assert(case,res)

class BaseJdbcAssert(ABC):
    """
    JDBC断言的基类
    """
    @abstractmethod
    def jdbc_assert(self,case):
        pass


class SingleJdbcAssert(BaseJdbcAssert):
    """
    JDBC单个断言，重写基类的jdbc_assert方法
    """
    def jdbc_assert(self, case):
        if case["sql_check"] and case["sql_expected"]:
            with allure.step("3.JDBC断言"):
                result = send_jdbc_request(case["sql_check"])
                logging.info(f"3.JDBC断言内容：预期结果（{case['sql_expected']}）in 实际结果（{result}）")
                assert case['sql_expected'] in str(result)


class MultipleJdbcAssert(BaseJdbcAssert):
    """
        JDBC多重断言，重写基类的jdbc_assert方法
    """
    def jdbc_assert(self,case):
        if case["sql_check"] and case["sql_expected"]:
            sql_check = eval(case["sql_check"])
            sql_expected = eval(case["sql_expected"])

            with allure.step("3.JDBC断言"):
                for sql, expected in zip(sql_check, sql_expected):
                    result = send_jdbc_request(sql)
                    logging.info(f"3.JDBC断言内容：预期结果（{expected}）in 实际结果（{result}）")
                    pytest.assume(expected in str(result))


def obj_jdbc_processor(case):
    """
        对象处理，根据传入case的不同，来返回不同的对象
    :param case: 测试用例
    :return: 单个断言/多个断言的对象
    """

    try:
        eval(case["sql_check"])
    except:
        return SingleJdbcAssert()
    else:
        return MultipleJdbcAssert()


def jdbc_assert(case):
    """
        真正的调用逻辑，后续无论怎么新增JDBC断言，都是调用这个函数
    :param case: 测试用例
    """
    obj_jdbc_processor(case).jdbc_assert(case)


